﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace Gebra
{
    public static class OperationHelper
    {
        /// <summary>
        /// Add "this" operand (<paramref name="a_this"/>) to the other given operand (<paramref name="a_other"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_other">Other operand.</param>
        /// <returns>Add operand.</returns>
        public static Add Add(this Operand a_this, Operand a_other)
        {
            return new Add(a_this, a_other);
        }

        /// <summary>
        /// Add "this" value (<paramref name="a_this"/>) to the other given operand (<paramref name="a_value"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_value">Value.</param>
        /// <returns>Add operand.</returns>
        public static Add Add(this Operand a_this, Complex a_value)
        {
            return new Add(a_this, (Number)a_value);
        }

        /// <summary>
        /// Multiply "this" operand (<paramref name="a_this"/>) to the other given operand (<paramref name="a_other"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_other">Other operand.</param>
        /// <returns>Multiple operand.</returns>
        public static Multiply Multiply(this Operand a_this, Operand a_other)
        {
            return new Multiply(a_this, a_other);
        }

        /// <summary>
        /// Multiply "this" value (<paramref name="a_this"/>) to the other given operand (<paramref name="a_value"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_value">Value.</param>
        /// <returns>Multiple operand.</returns>
        public static Multiply Multiply(this Operand a_this, Complex a_value)
        {
            return new Multiply(a_this, (Number)a_value);
        }

        /// <summary>
        /// Subtract the other given operand (<paramref name="a_other"/>) from "this" one (<paramref name="a_this"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_other">Other operand.</param>
        /// <returns>Subtract operation.</returns>
        public static Subtract Subtract(this Operand a_this, Operand a_other)
        {
            return new Subtract(a_this, a_other);
        }

        /// <summary>
        /// Subtract the other given value (<paramref name="a_value"/>) from "this" one (<paramref name="a_this"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_value">Value.</param>
        /// <returns>Subtract operation.</returns>
        public static Subtract Subtract(this Operand a_this, Complex a_value)
        {
            return new Subtract(a_this, (Number)a_value);
        }

        /// <summary>
        /// Divide the other given operand (<paramref name="a_other"/>) from "this" one (<paramref name="a_this"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_other">Other operand.</param>
        /// <returns>Divide operand.</returns>
        public static Divide Divide(this Operand a_this, Operand a_other)
        {
            return new Divide(a_this, a_other);
        }
        /// <summary>
        /// Divide the other given value (<paramref name="a_value"/>) from "this" one (<paramref name="a_this"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_value">Value.</param>
        /// <returns>Divide operand.</returns>
        public static Divide Divide(this Operand a_this, Complex a_value)
        {
            return new Divide(a_this, (Number)a_value);
        }

        /// <summary>
        /// Raise "this" operand (<paramref name="a_this"/>) by the other given operand (<paramref name="a_other"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_other">Other operand.</param>
        /// <returns>Exponent operand.</returns>
        public static Exponent Raise(this Operand a_this, Operand a_other)
        {
            return new Exponent(a_this, a_other);
        }

        /// <summary>
        /// Raise "this" operand (<paramref name="a_this"/>) by the given value (<paramref name="a_value"/>).
        /// </summary>
        /// <param name="a_this">"This" operand.</param>
        /// <param name="a_value">Value.</param>
        /// <returns>Exponent operand.</returns>
        public static Exponent Raise(this Operand a_this, Complex a_value)
        {
            return new Exponent(a_this, (Number)a_value);
        }

        /// <summary>
        /// Measure the distance between "this" complex number (<paramref name="a_this"/>) and the other complex number (<paramref name="a_other"/>).
        /// </summary>
        /// <param name="a_this">"This" complex number.</param>
        /// <param name="a_other">Other complex number.</param>
        /// <returns></returns>
        public static double Distance(this Complex a_this, Complex a_other)
        {
            return Math.Sqrt(Math.Pow(a_this.Real - a_other.Real, 2) + Math.Pow(a_this.Imaginary - a_other.Imaginary, 2));
        }
    }
}
